/*版本说明：
一.本版本增加功能如下：
   1.结束包的检测，扣留
   2.重传结束包的丢弃
   3.增加一个消息队列，用于“判决意见”的传输
二.本版本的实现效果：
   1.发现结束包后，扣留之。
   2.同时，对于其他类型的数据包，正常放行。
   3.当消息队列中，收到判决意见后，从阻拦索中取出扣留的对应数据包，放行之
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <netinet/ip_icmp.h>
#include <netinet/ip.h>
#include <arpa/inet.h>

#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>

#include "libipq.h"
#include "calculate.h"
#include "mem_manage.h"
#include "doggie.h"
#include "my_msg_queue.h"


#define ETH_HDRLEN 14
#define NF_ACCEPT 	1
#define NF_DROP  	0


#define FIFO_NAME	"myfifo"

typedef struct{
	struct iphdr iph;
	struct icmphdr icmph;
} ip_icmp_packet_s;

struct ipq_handle *h = NULL;

static void sig_int(int signo)
{
	ipq_destroy_handle(h);
	printf("Exit: %s\n", ipq_errstr());
	exit(0);
}




int main(void)
{
	unsigned char buf[1500];
	union_num unum;
	int count=0;

	//int door;
	int pacLen;//


//-------------------消息队列-------------------------
	int queueid;
	
	queueid=getMsgQueue();
	
//---------------------------------------------------
	

//-------------------共享内存-------------------------
	int semid;
	void *smptr;
	semid=getSem(SEM_NAME,SEM_ID,OPEN);
	mem_start=getMem(MEM_NAME,MEM_ID,TOTAL_LEN,OPEN);
	smptr=mem_start; 
	
//---------------------------------------------------

//-------------------阻拦索-----------------------
	QueueHead * my_qhead;
        my_qhead=init_intercept_queue();
	
//---------------------------------------------------

	
	h = ipq_create_handle(0, PF_INET);//创建netlink套接字
	if(h == NULL)
	{
		printf("%s\n", ipq_errstr());
		return 0;
	}
	printf("ipq_creat_handle success!\n");
	
	/*设置消息类型为：模式消息*/
	unsigned char mode = IPQ_COPY_PACKET;
	int range = sizeof(buf);
	int ret = ipq_set_mode(h, mode, range);
	printf("ipq_set_mode: send bytes =%d, range=%d\n", ret, range);
	
	/*register signal handler*/
	signal(SIGINT, sig_int);

	/*read packet from kernel*/
	int status;
	struct nlmsghdr *nlh;
	ipq_packet_msg_t *ipq_packet;
	
	while(1)
	{
		int i=0;
		status = ipq_read(h, buf, sizeof(buf));
		if(status > sizeof(struct nlmsghdr))
		{
			nlh = (struct nlmsghdr *)buf;
			ipq_packet = ipq_get_packet(buf);
			
			//count++;
			
			unsigned char payload[1500];

			memset(payload, 0x00, sizeof(payload));

			pacLen=ipq_packet->data_len;
			memcpy(payload, ipq_packet->payload, pacLen);
			
			//---阻拦索-------------------------------------------------------------------------------------
			//检查到达的数据包，是否为结束包
			if(checkEndPack(ipq_packet->payload,pacLen)==1)
			{
				//为结束包构造LinkId,即这个数据包的四元组 
				LinkId *lid;
				lid=getLinkId(ipq_packet->payload);

				//检查这个结束包，是否已经在扣留队列中
				if(checkQueue(my_qhead,lid)==1)
				{
					//如果是重传包，那么丢弃
					ret = ipq_set_verdict(h, ipq_packet->packet_id, NF_DROP,pacLen,payload);
					free(lid);
				}
				else//如果一个结束包不在队列中，说明是新的结束包
				{
					PacketElem * packet_elem;
					packet_elem=getPack(ipq_packet->payload,lid,ipq_packet->packet_id,pacLen);
					//把结束包，加入扣留队列					
					enQueue(my_qhead,packet_elem);
					
					//同时，把该数据写到缓冲区（即发给 处理进程）
					while(fuckwrite(&smptr,payload,pacLen,semid)!=T_OK)
					{

						count++;
					//	printf("%dst, write wait~!\n\n",count);
						sleep(1);

					}
				}

			}
			else//对于其他类型的数据包，直接放行
			{
				while(fuckwrite(&smptr,payload,pacLen,semid)!=T_OK)
				{

					count++;
				    //	printf("%dst, write wait~!\n\n",count);
					sleep(1);
				}
		
				ret = ipq_set_verdict(h, ipq_packet->packet_id, NF_ACCEPT,pacLen,payload);
			}
			

                        //------------------------------------------------------
                        //read judge order from " mail spam module"
			//------------------------------------------------------
	 		Judge_Msg mymsg;
			int msg_len=sizeof(Judge_Msg)-4;
			
			//读取消息队列,看看有没有 "判决意见" 到达
			if(msgrcv(queueid,&mymsg,msg_len,5,IPC_NOWAIT)==-1)
			{
			//	printf("no message in queue\n");
			}
			else
			{
				
				PacketElem * temp_packet;
				LinkId * temp_lid;
				int judgement=-1;

				temp_lid = (LinkId *)&mymsg.judge_order.pacid;
				judgement=mymsg.judge_order.judge;
				temp_packet=delOnePac(my_qhead,temp_lid);

				if(judgement>0)
				{	
					//如果有判决意见到达，根据其信息，到队列中找到对应数据包，放行				
					//temp_packet=delOnePac(my_qhead,temp_lid);
					//printf("ready to release one packet~!\n");
					printf("get a pass judge!\n");
					ret = ipq_set_verdict(h, temp_packet->packet_id, NF_ACCEPT,temp_packet->pacLen,temp_packet->data);
				
				}
				else
				{
					printf("get a cut judge!\n");
					ret = ipq_set_verdict(h, temp_packet->packet_id, NF_DROP,temp_packet->pacLen,temp_packet->data);
				}
				printf("brfore clean!\n");
				//回收数据包内存资源				
				mem_cleaner(temp_packet);
			}
			/*  
		 	My_Msg mymsg;
			int msg_len=sizeof(My_Msg)-4;
			
			//读取消息队列,看看有没有 "判决意见" 到达
			if(msgrcv(queueid,&mymsg,msg_len,5,IPC_NOWAIT)==-1)
			{
			//	printf("no message in queue\n");
			}
			else
			{
				
				PacketElem * temp_packet;
				LinkId * temp_lid;
				temp_lid = (LinkId *)&mymsg.pacid;
				//如果有判决意见到达，根据其信息，到队列中找到对应数据包，放行				
				temp_packet=delOnePac(my_qhead,temp_lid);
				//printf("ready to release one packet~!\n");
				ret = ipq_set_verdict(h, temp_packet->packet_id, NF_ACCEPT,temp_packet->pacLen,temp_packet->data);
				//回收数据包内存资源				
				mem_cleaner(temp_packet);
			}
			*/	
			

		}
	}
	return 0;
}
